package loader

import (
	"strings"

	"github.com/joho/godotenv"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"xincan.com.cn/tarot-go/internal/components/logging"
)

// envApplicationConfigLoader
// Title 				envApplicationConfigLoader
// Description 			全局参数配置: 加载系统环境变量, 并加载到全局变量中
// Author  				alittlexincan@163.com 					2024/07/22 11:36
// Update  				alittlexincan@163.com 					2024/07/22 11:36
type envApplicationConfigLoader struct {

	// localViper 本地配置实例
	localViper *viper.Viper

	// logger 日志实例
	logger *logging.TraceLogger
}

// EnvApplicationConfigLoaderBuilder
// Title 				EnvApplicationConfigLoaderBuilder
// Description 			环境变量配置构建器
// Author 				alittlexincan@163.com 					2024/07/22 11:36
// Update  				alittlexincan@163.com 					2024/07/22 11:36
type EnvApplicationConfigLoaderBuilder struct {

	// envApplicationConfigLoader 	本地参数配置
	*envApplicationConfigLoader
}

// NewEnvApplicationConfigLoaderBuilder
// Title 				NewEnvApplicationConfigLoaderBuilder
// Description 			创建环境变量配置构建器
// Author  				alittlexincan@163.com 									2024/07/22 11:36
// Update  				alittlexincan@163.com 									2024/07/22 11:36
// Return    			*EnvApplicationConfigLoaderBuilder     					环境变量配置构建器实例
func NewEnvApplicationConfigLoaderBuilder() *EnvApplicationConfigLoaderBuilder {
	return &EnvApplicationConfigLoaderBuilder{
		envApplicationConfigLoader: &envApplicationConfigLoader{},
	}
}

// WithLocalViper
// Title 				WithLocalViper
// Description 			构造器: 配置本地参数配置实例
// Author      			alittlexincan@163.com       							2024/07/22 11:36
// Update    			alittlexincan@163.com       							2024/07/22 11:36
// Param    			localViper 						*viper.Viper			本地参数配置实例
// Return    			*EnvApplicationConfigLoaderBuilder     					环境变量配置构建器实例
func (builder *EnvApplicationConfigLoaderBuilder) WithLocalViper(localViper *viper.Viper) *EnvApplicationConfigLoaderBuilder {
	builder.localViper = localViper
	return builder
}

// WithLogger
// Title 				WithLogger
// Description 			构造器: 加载日志配置
// Author      			alittlexincan@163.com       							2024/07/22 11:36
// Update    			alittlexincan@163.com       							2024/07/22 11:36
// Param    			logger 						*logging.TraceLogger		日志实例
// Return    			*EnvApplicationConfigLoaderBuilder     					环境变量配置构建器实例
func (builder *EnvApplicationConfigLoaderBuilder) WithLogger(logger *logging.TraceLogger) *EnvApplicationConfigLoaderBuilder {
	builder.logger = logger
	return builder
}

// Build
// Title 				Build
// Description 			构造器: 构建环境变量配置实例
// Author      			alittlexincan@163.com       							2024/07/22 11:36
// Update    			alittlexincan@163.com       							2024/07/22 11:36
// Return    			*viper.Viper     										环境变量配置实例
func (builder *EnvApplicationConfigLoaderBuilder) Build() *viper.Viper {
	return builder.ConfigLoad()
}

// ConfigLoad
// Title 				ConfigLoad
// Description 			加载环境变量配置信息
// Author      			alittlexincan@163.com       							2024/07/22 11:36
// Update    			alittlexincan@163.com       							2024/07/22 11:36
// Return    			*viper.Viper     										环境变量配置实例
func (env *envApplicationConfigLoader) ConfigLoad() *viper.Viper {
	// 1. 使用 godotenv 加载 .env 文件中的变量到系统环境变量
	// 如果文件不存在，这里会报错，对于依赖 .env 文件的场景是合理的
	if err := godotenv.Load(); err != nil {
		env.logger.Error("加载环境变量失败", zap.Error(err))
		return nil
	}
	// 2. 创建 viper 实例, 绑定环境变量
	envViper := viper.New()
	envViper.SetConfigType("yaml")
	envViper.AutomaticEnv()
	envViper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	// 系统基础信息
	_ = envViper.BindEnv("application.ip", "APP_ADDR")
	_ = envViper.BindEnv("application.port", "APP_PORT")
	_ = envViper.BindEnv("application.active", "APP_ACTIVE")
	_ = envViper.BindEnv("application.name", "APP_NAME")
	_ = envViper.BindEnv("application.node", "APP_NODE")
	// nacos 注册中心
	_ = envViper.BindEnv("application.registry.nacos.ip", "NACOS_SERVER_ADDRESS")
	_ = envViper.BindEnv("application.registry.nacos.port", "NACOS_SERVER_PORT")
	_ = envViper.BindEnv("application.registry.nacos.username", "NACOS_USERNAME")
	_ = envViper.BindEnv("application.registry.nacos.password", "NACOS_PASSWORD")
	_ = envViper.BindEnv("application.registry.nacos.namespaceId", "NACOS_NAMESPACE_ID")
	_ = envViper.BindEnv("application.registry.nacos.group", "NACOS_GROUP")
	// nacos 配置中心
	_ = envViper.BindEnv("application.config.nacos.ip", "NACOS_SERVER_ADDRESS")
	_ = envViper.BindEnv("application.config.nacos.port", "NACOS_SERVER_PORT")
	_ = envViper.BindEnv("application.config.nacos.username", "NACOS_USERNAME")
	_ = envViper.BindEnv("application.config.nacos.password", "NACOS_PASSWORD")
	_ = envViper.BindEnv("application.config.nacos.namespaceId", "NACOS_NAMESPACE_ID")
	_ = envViper.BindEnv("application.config.nacos.group", "NACOS_GROUP")
	_ = envViper.BindEnv("application.config.nacos.dataId", "NACOS_DATA_ID")
	// 3. 获取所有环境变量
	envData := envViper.AllSettings()
	if len(envData) == 0 {
		env.logger.Error("系统环境变量配置: 当前未设置系统环境变量")
		return nil
	}
	// 4. 打印环境变量, 合并环境变量到本地参数配置实例
	env.logger.Info("加载环境变量配置: ", zap.Any("env", envData))
	env.safeMergeSettings(envData, "")
	env.logger.Info("合并环境变量配置成功: ", zap.Any("env", env.localViper.AllSettings()))
	return envViper
}

// safeMergeSettings
// Title 				safeMergeSettings
// Description 			递归合并源Map到目标Viper实例，仅处理源中存在的叶子节点（具体配置值）
// Author      			alittlexincan@163.com       							2024/07/22 11:36
// Update    			alittlexincan@163.com       							2024/07/22 11:36
// Param    			sourceMap 						map[string]interface{}	env 配置信息
// Param    			prefix 							string					前缀
func (env *envApplicationConfigLoader) safeMergeSettings(sourceMap map[string]interface{}, prefix string) {
	for key, sourceValue := range sourceMap {
		fullKey := key
		if prefix != "" {
			fullKey = prefix + "." + key
		}
		// 尝试将源值转换为 map[string]interface{}
		if sourceSubMap, sourceIsMap := sourceValue.(map[string]interface{}); sourceIsMap {
			// 如果源值是一个Map，递归处理子Map
			env.safeMergeSettings(sourceSubMap, fullKey)
		} else {
			// 如果源值不是Map（即是一个具体的配置值，如字符串、数字等），则进行设置
			// 关键点：只有明确在环境变量中设置了的叶子节点值才会被覆盖
			env.localViper.Set(fullKey, sourceValue)
		}
	}
}
